/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import ts from '~/vendor/ohos-typescript';

import { Location } from '~/type/Generic';
import { EngineCapability } from '~/dsl';

import { MockRule } from './MockRule';
import { MockConfig, MockHint, MockIssue } from './MockHint';

/**
 * Represents the native engine.
 */
export class MockEngine {
    private config: MockConfig = {};
    private nodes: ts.Node[] = [];
    private lines: number[] = [];

    /**
     * Required for every native engine.
     */
    public getCapabilities(): EngineCapability<MockHint> {
        return {
            name: 'mock',
            config: this.config,
            api: {
                getLocation: (node: ts.Node): Location => {
                    return {
                        file: '',
                        range: {
                            start: {
                                line: node.pos,
                                column: 0,
                            },
                            end: {
                                line: node.pos,
                                column: 0,
                            },
                        },
                    };
                },

                report: (issue: MockIssue) => {
                    this.report(issue);
                },
            },
            native: {
                // Why version is native? Just a demo.
                version: '0.1.0',
            },
        };
    }

    /**
     * The actual engines may load configuration from file or command line arguments.
     */
    public configure(config: Partial<MockConfig>): void {
        this.config = { ...this.config, ...config };
    }

    /**
     * The unified entry for the engine to execute native checks/rules.
     * @param rules
     */
    public submit(rules: MockRule[]): void {
        for (const node of this.nodes) {
            for (const rule of rules) {
                if (rule.pattern(node)) {
                    rule.callback(node);
                }
            }
        }
    }

    /**
     * Test only, doesn't exist in the real engine.
     *
     * @internal
     */
    public addNode(node: ts.Node): MockEngine {
        this.nodes.push(node);
        return this;
    }

    /**
     * Test only, doesn't exist in the real engine.
     *
     * @internal
     */
    public clear(): void {
        this.lines = [];
    }

    /**
     * Test only, doesn't exist in the real engine.
     *
     * @internal
     */
    public getIssueLines(): number[] {
        return this.lines;
    }

    private report(issue: MockIssue): void {
        console.log(`[ISSUE] Line ${issue.line}: ${issue.message}`);
        this.lines.push(issue.line);
    }
}

export const mockEngine = new MockEngine();
